package services

import (
	"context"
	"encoding/json"
	"sanrenx.com/xyxf/app/daos"
	"sanrenx.com/xyxf/app/models"
	"sanrenx.com/xyxf/app/services/cache"
	"sanrenx.com/xyxf/pkg/gredis"
	"sanrenx.com/xyxf/pkg/logging"
	"sanrenx.com/xyxf/pkg/orm"
	"strconv"
)

/**
 * @Description: 问答
 */
type IssueSrv struct{}

/**
 * @Description: 分页获取问题列表
 * @receiver srv
 * @param offset 起始
 * @param size 数量
 * @param orderBy 排序方式
 * @return list 问题列表
 * @return err 异常信息
 */
func (srv *IssueSrv) GetPageIssueBySolve(offset int64, size int64, solve bool) (list []*models.Issue, err error) {
	var (
		cacheSrv cache.IssueCache
		dataIDs  []string
		orderBy  string
	)

	//解决
	if solve {
		orderBy = models.OrderIssueSame
	} else {
		orderBy = models.OrderIssuePraise
	}

	ctx := context.Background()
	//不同排序缓存key
	listKey := cacheSrv.GetZSetKey(orderBy)
	//热度缓存KEY 需要增加key到被缓存key中 更新热度
	_ = gredis.ZAdd(ctx, cacheSrv.GetCacheHotKey(orderBy), listKey, 7)

	//从缓存中获取分页ID
	if dataIDs, err = gredis.ZRevRange(ctx, listKey, offset, offset+size-1); err != nil {
		logging.Error(err)
		return nil, err
	}

	//补救缓存
	if len(dataIDs) < int(size) {
		issueDao := daos.IssueDao{DB: orm.DB}
		cacheCount, _ := gredis.ZCard(ctx, listKey) //缓存中数量
		maps := map[string]interface{}{
			"solve": solve,
		}

		dbCount, _ := issueDao.GetIssueCount(maps) //数据库中数量
		//不统一需要同步
		if cacheCount < dbCount {
			//获取数据库中数据
			dbIds, columns, err := issueDao.GetPageIssueColumn(maps, 0, int(dbCount), orderBy)
			if err != nil {
				return nil, err
			}

			//补充到数据库
			for _, column := range columns {
				if orderBy == models.OrderIssueSame {
					_ = gredis.ZAdd(ctx, listKey, column.ID, float64(column.Same))
				} else if orderBy == models.OrderIssuePraise {
					_ = gredis.ZAdd(ctx, listKey, column.ID, float64(column.Praise))
				}
			}

			//获取当前分页数组
			if dbCount > offset {
				var end int64
				diff := dbCount - offset
				if diff > 0 {
					if diff > size {
						end = offset + size
					} else {
						end = offset + diff
					}
					//最大可获得
					dataIDs = dbIds[offset:end]
				}
			}
		}
	}

	//根据缓存ID 获取结构体信息
	for _, cacheID := range dataIDs {
		details := new(models.IssueDetails)

		id, _ := strconv.ParseUint(cacheID, 10, 64)
		dataKey := cacheSrv.GetDataKey(id)
		//数据在缓存中，获取数据
		if gredis.Exist(ctx, dataKey) {
			var cacheData string
			cacheData, err = gredis.Get(ctx, dataKey)
			if err == nil {
				err = json.Unmarshal([]byte(cacheData), &details)
			}
		} else {
			//缓存中没找到，刷新缓存获取数据
			details, err = srv.RefreshCacheIssueById(id)
		}

		//检查err
		if err != nil || details == nil {
			logging.Error(err)
			continue
		}

		//返回结构体
		list = append(list, &models.Issue{
			Title:   details.Title,
			Same:    details.Same,
			Praise:  details.Praise,
			Solve:   details.Solve,
			Anon:    details.Anon,
			Quizzer: details.Quizzer,
			Solver:  details.Keyman,
		})
	}

	return list, nil
}

/**
 * @Description: 获取问题详情
 * @receiver srv
 * @param id 问题ID
 * @return data 问题详情
 * @return err 异常信息
 */
func (srv *IssueSrv) GetIssueById(id uint64) (data *models.IssueDetails, err error) {
	var cacheSrv cache.IssueCache
	//查找Redis缓存
	dataKey := cacheSrv.GetDataKey(id)
	ctx := context.Background()
	if gredis.Exist(ctx, dataKey) {
		cacheData, err := gredis.Get(ctx, dataKey)
		if err != nil {
			logging.Info(err)
		} else {
			_ = json.Unmarshal([]byte(cacheData), &data)
			return data, nil
		}
	}

	//刷新缓存，同时获取数据
	if data, err = srv.RefreshCacheIssueById(id); err != nil {
		return nil, err
	}

	return data, nil
}

/**
 * @Description: 刷新缓存问题
 * @receiver srv
 * @param id 问题ID
 * @return data 问题详情
 * @return err 异常
 */
func (srv *IssueSrv) RefreshCacheIssueById(id uint64) (data *models.IssueDetails, err error) {

	modelDao := daos.IssueDao{DB: orm.DB}
	//根据ID查找数据库获取文章
	if data, err = modelDao.GetIssue(id); err != nil {
		logging.Error(err)
		return nil, err
	}

	//更新缓存
	var cacheSrv cache.IssueCache
	dataKey := cacheSrv.GetDataKey(id)
	//写一个String缓存, 过期时间1小时
	ctx := context.Background()
	_ = gredis.Set(ctx, dataKey, data, cache.IssueExpireTime)

	//更新缓存列表中 热度分值
	RefreshCacheKeyHot(cacheSrv.GetCacheHotKey(models.OrderIssueSame), data.ID, data.Same)
	RefreshCacheKeyHot(cacheSrv.GetCacheHotKey(models.OrderIssuePraise), data.ID, data.Praise)

	return data, nil
}
